package org.cybzacg.encryption.exception;

import org.cybzacg.encryption.enums.EncryptionStatus;
import org.cybzacg.encryption.context.EncryptionContext;

/**
 * 加密异常基类
 * 所有加密相关异常的基类
 * 
 * @author encryption team
 * @version 1.0
 */
public class EncryptionException extends RuntimeException {
    
    private final EncryptionStatus status;
    private final EncryptionContext context;
    private final String errorCode;
    private final boolean retryable;
    
    /**
     * 构造函数
     * 
     * @param message 错误消息
     */
    public EncryptionException(String message) {
        this(message, EncryptionStatus.UNKNOWN_ERROR, null, null, false);
    }
    
    /**
     * 构造函数
     * 
     * @param message 错误消息
     * @param cause 原因
     */
    public EncryptionException(String message, Throwable cause) {
        this(message, EncryptionStatus.UNKNOWN_ERROR, null, cause, false);
    }
    
    /**
     * 构造函数
     * 
     * @param message 错误消息
     * @param status 状态
     */
    public EncryptionException(String message, EncryptionStatus status) {
        this(message, status, null, null, status.isRetryable());
    }
    
    /**
     * 构造函数
     * 
     * @param message 错误消息
     * @param status 状态
     * @param context 上下文
     */
    public EncryptionException(String message, EncryptionStatus status, EncryptionContext context) {
        this(message, status, context, null, status.isRetryable());
    }
    
    /**
     * 构造函数
     * 
     * @param message 错误消息
     * @param status 状态
     * @param context 上下文
     * @param cause 原因
     */
    public EncryptionException(String message, EncryptionStatus status, EncryptionContext context, Throwable cause) {
        this(message, status, context, cause, status.isRetryable());
    }
    
    /**
     * 构造函数
     * 
     * @param message 错误消息
     * @param status 状态
     * @param context 上下文
     * @param cause 原因
     * @param retryable 是否可重试
     */
    public EncryptionException(String message, EncryptionStatus status, EncryptionContext context, Throwable cause, boolean retryable) {
        super(message, cause);
        this.status = status != null ? status : EncryptionStatus.UNKNOWN_ERROR;
        this.context = context;
        this.errorCode = generateErrorCode(this.status);
        this.retryable = retryable;
    }
    
    /**
     * 构造函数
     * 
     * @param message 错误消息
     * @param errorCode 错误代码
     * @param context 上下文
     * @param cause 原因
     * @param retryable 是否可重试
     */
    public EncryptionException(String message, String errorCode, EncryptionContext context, Throwable cause, boolean retryable) {
        super(message, cause);
        this.status = EncryptionStatus.UNKNOWN_ERROR;
        this.context = context;
        this.errorCode = errorCode;
        this.retryable = retryable;
    }
    
    /**
     * 获取状态
     * 
     * @return 状态
     */
    public EncryptionStatus getStatus() {
        return status;
    }
    
    /**
     * 获取上下文
     * 
     * @return 上下文
     */
    public EncryptionContext getContext() {
        return context;
    }
    
    /**
     * 获取错误代码
     * 
     * @return 错误代码
     */
    public String getErrorCode() {
        return errorCode;
    }
    
    /**
     * 检查是否可重试
     * 
     * @return 是否可重试
     */
    public boolean isRetryable() {
        return retryable;
    }
    
    /**
     * 生成错误代码
     * 
     * @param status 状态
     * @return 错误代码
     */
    private String generateErrorCode(EncryptionStatus status) {
        return "ENC_" + status.name();
    }
    
    /**
     * 创建密钥无效异常
     * 
     * @param message 错误消息
     * @param context 上下文
     * @return 异常
     */
    public static EncryptionException invalidKey(String message, EncryptionContext context) {
        return new EncryptionException(message, EncryptionStatus.INVALID_KEY, context);
    }
    
    /**
     * 创建算法不支持异常
     * 
     * @param message 错误消息
     * @param context 上下文
     * @return 异常
     */
    public static EncryptionException algorithmNotSupported(String message, EncryptionContext context) {
        return new EncryptionException(message, EncryptionStatus.ALGORITHM_NOT_SUPPORTED, context);
    }
    
    /**
     * 创建数据格式错误异常
     * 
     * @param message 错误消息
     * @param context 上下文
     * @return 异常
     */
    public static EncryptionException invalidDataFormat(String message, EncryptionContext context) {
        return new EncryptionException(message, EncryptionStatus.INVALID_DATA_FORMAT, context);
    }
    
    /**
     * 创建配置错误异常
     * 
     * @param message 错误消息
     * @param context 上下文
     * @return 异常
     */
    public static EncryptionException configurationError(String message, EncryptionContext context) {
        return new EncryptionException(message, EncryptionStatus.CONFIGURATION_ERROR, context);
    }
    
    /**
     * 创建超时异常
     * 
     * @param message 错误消息
     * @param context 上下文
     * @return 异常
     */
    public static EncryptionException timeout(String message, EncryptionContext context) {
        return new EncryptionException(message, EncryptionStatus.TIMEOUT, context, null, true);
    }
    
    /**
     * 创建网络错误异常
     * 
     * @param message 错误消息
     * @param context 上下文
     * @param cause 原因
     * @return 异常
     */
    public static EncryptionException networkError(String message, EncryptionContext context, Throwable cause) {
        return new EncryptionException(message, EncryptionStatus.NETWORK_ERROR, context, cause, true);
    }
    
    /**
     * 创建权限不足异常
     * 
     * @param message 错误消息
     * @param context 上下文
     * @return 异常
     */
    public static EncryptionException permissionDenied(String message, EncryptionContext context) {
        return new EncryptionException(message, EncryptionStatus.PERMISSION_DENIED, context);
    }
    
    /**
     * 创建内存不足异常
     * 
     * @param message 错误消息
     * @param context 上下文
     * @param cause 原因
     * @return 异常
     */
    public static EncryptionException outOfMemory(String message, EncryptionContext context, Throwable cause) {
        return new EncryptionException(message, EncryptionStatus.OUT_OF_MEMORY, context, cause);
    }
    
    @Override
    public String toString() {
        return "EncryptionException{" +
                "message='" + getMessage() + '\'' +
                ", status=" + status +
                ", errorCode='" + errorCode + '\'' +
                ", retryable=" + retryable +
                ", context=" + (context != null ? context.getContextId() : "null") +
                '}';
    }
}
